package logic

import (
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"img_analyse/analyse/api/service_rpc"
	"img_analyse/analyse/model"
	"io"
	"time"

	"img_analyse/analyse/api/internal/svc"
	"img_analyse/analyse/api/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UploadImageLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUploadImageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadImageLogic {
	return &UploadImageLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UploadImageLogic) UploadImage(req *types.ImageUploadRequest) (*types.UploadResponse, error) {
	// 1. 增强文件校验
	if req == nil || req.File == nil {
		l.Logger.Error("请求参数或文件为空")
		return nil, errors.New("请求参数不完整")
	}

	// 2. 读取文件（带超时控制）
	ctx, cancel := context.WithTimeout(l.ctx, 30*time.Second) // 延长总超时时间
	defer cancel()

	file, err := req.File.Open()
	if err != nil {
		l.Logger.Errorf("文件打开失败: %v", err)
		return nil, errors.New("文件读取失败")
	}
	defer file.Close()

	// 3. 限制文件大小（防止内存溢出）
	maxSize := 10 << 20 // 10MB
	fileData, err := io.ReadAll(io.LimitReader(file, int64(maxSize+1)))
	if err != nil {
		l.Logger.Errorf("文件读取失败: %v", err)
		return nil, errors.New("文件读取失败")
	}
	if len(fileData) > maxSize {
		return nil, errors.New("文件大小超过10MB限制")
	}

	// 4. 建立gRPC连接（带重试机制）
	var conn *grpc.ClientConn
	for i := 0; i < 3; i++ { // 重试3次
		conn, err = grpc.DialContext(
			ctx,
			"localhost:50051",
			grpc.WithTransportCredentials(insecure.NewCredentials()),
			grpc.WithBlock(),
			grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(50<<20)), // 50MB
		)
		if err == nil {
			break
		}
		time.Sleep(time.Second * time.Duration(i+1)) // 指数退避
	}
	if err != nil {
		l.Logger.Errorf("gRPC连接失败: %v", err)
		return nil, errors.New("服务暂时不可用")
	}
	defer conn.Close()

	// 5. 调用RPC服务
	client := pb.NewImageServiceClient(conn)
	rpcResp, err := client.UploadImage(ctx, &pb.ImageUploadRequest{
		File: base64.StdEncoding.EncodeToString(fileData),
	})
	if err != nil {
		l.Logger.Errorf("RPC调用失败: %v", err)
		return nil, fmt.Errorf("图像处理失败: %v", err)
	}

	// 修改RPC响应检查逻辑
	if rpcResp == nil {
		l.Logger.Error("RPC返回空响应")
		return nil, errors.New("服务无响应")
	}

	// 更详细的响应数据检查
	if rpcResp.Code != 200 {
		l.Logger.Errorf("RPC返回错误状态码: %d, 消息: %s", rpcResp.Code, rpcResp.Msg)
		return nil, fmt.Errorf("图像处理错误: %s", rpcResp.Msg)
	}

	if rpcResp.Data == nil {
		l.Logger.Error("RPC返回数据为空")
		return nil, errors.New("服务返回数据不完整")
	}

	// 检查关键字段
	if rpcResp.Data.Url == "" || rpcResp.Data.Newurl == "" {
		l.Logger.Error("RPC返回URL为空")
		return nil, errors.New("服务返回无效路径")
	}

	// 7. 数据库操作
	if err := l.svcCtx.DB.WithContext(ctx).Create(&model.Image{
		Name:    rpcResp.Data.Name,
		URL:     rpcResp.Data.Url,
		NewName: rpcResp.Data.Newname,
		NewURL:  rpcResp.Data.Newurl,
	}).Error; err != nil {
		l.Logger.Errorf("数据库写入失败: %v", err)
		return nil, errors.New("数据保存失败")
	}

	return &types.UploadResponse{
		Code: int(rpcResp.Code),
		Data: types.ImageInfo{
			Name:    rpcResp.Data.Name,
			URL:     rpcResp.Data.Url,
			NewName: rpcResp.Data.Newname,
			NewURL:  rpcResp.Data.Newurl,
		},
		Msg: rpcResp.Msg,
	}, nil
}
